<?php
namespace App\Utils\WechatSdk;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Psr7\Request;

class WeChatOperator {
	/**
	 * 微信接口调用所需配置参数
	 */
	const NONCE_LENGTH = 16;


	/**
	 * 使用guzzle发送http请求的默认配置参数
	 */
	const DEFAULT_HTTP_TIMEOUT = 3;
	const DEFAULT_REPEAT_TIMES = 3;


	/**
	 * [checkSignature 验证签名是否正确]
	 * @param  string $signature [微信加密签名]
	 * @param  number $timestamp [时间戳，10位数字，精确到秒]
	 * @param  number $nonce     [随机数]
	 * @return boolean           [true:验证通过；false:验证不通过]
	 */
	public static function checkSignature($signature, $timestamp, $nonce) { 		
		$tmpStr = self::genSignature($timestamp, $nonce);
		
		if( $tmpStr == $signature ){
			return true;
		}else{
			return false;
		}
	}


	/**
	 * [genSignature sha1算法生成签名并返回]
	 * @param  number $timestamp [时间戳，10位数字，精确到秒]
	 * @param  number $nonce     [随机数]	 
	 * @return string            [sha1加密算法生成签名]
	 */
	public static function genSignature($timestamp, $nonce){
		$token = env('WECHAT_TOKEN');
		$tmpArr = array($token, $timestamp, $nonce);
		sort($tmpArr, SORT_STRING);
		$tmpStr = implode($tmpArr);
		$tmpStr = sha1($tmpStr);

		return $tmpStr;
	}


	/**
	 * [getAccessTokenFromHttp 通过http请求调用微信接口，获取微信接口调用凭证，并将请求结果封装为ResponseModel对象]
	 * @param  string $method     [http请求方法]
	 * @param  string $url        [http请求地址]
	 * @param  string $grant_type [获取access_token填写client_credential]
	 * @param  number $timeout    [超时设置，精确到秒；0为不设置]
	 * @return ResponseModel      [返回值]
	 */
	public static function getAccessTokenFromHttp($method='GET', $url='/cgi-bin/token', $grant_type='client_credential', $timeout=self::DEFAULT_HTTP_TIMEOUT){
		$client = new Client(['base_uri' => env('WECHAT_BASE_URI'), 'timeout' => $timeout]);
		$query = array('grant_type' => $grant_type, 'appid' => env('WECHAT_APP_ID'), 'secret' => env('WECHAT_APP_SECRET'));
		$options = array('query' => $query);

		$result = SendRequestOperator::sendRequest($client, $method, $url, $options);
		return $result;
	}


	/**
	 * [getAccessToken 若当前存储的access_token仍在生命周期内，则直接返回ResponseModel对象]
	 * @param  string $method     [http请求方法]
	 * @param  string $url        [http请求地址]
	 * @param  string $grant_type [获取access_token填写client_credential]
	 * @param  number $timeout    [超时设置，精确到秒；0为不设置]
	 * @return ResponseModel      [返回值]
	 */
	public static function getAccessToken($method='GET', $url='/cgi-bin/token', $grant_type='client_credential', $timeout=self::DEFAULT_HTTP_TIMEOUT){
		

		return self::getAccessTokenFromHttp($method, $url, $grant_type, $timeout);
	}


	public static function getQRCodeTicket($data, $accessToken, $method='POST', $url='/cgi-bin/qrcode/create', $timeout=self::DEFAULT_HTTP_TIMEOUT){
		if( is_array($data) ){
			$data = json_encode($data);
		}

		$client = new Client(['base_uri' => env('WECHAT_BASE_URI'), 'timeout' => $timeout]);
		$query = array('access_token' => $accessToken);
		$options = array('query' => $query, 'body' => $data);

		return SendRequestOperator::sendRequest($client, $method, $url, $options);
	}


	public static function sendTemplateMessage($data, $accessToken, $method='POST', $url='/cgi-bin/message/template/send', $timeout=self::DEFAULT_HTTP_TIMEOUT){
		if( is_array($data) ){
			$data = json_encode($data);
		}

		$client = new Client(['base_uri' => env('WECHAT_BASE_URI'), 'timeout' => $timeout]);
		$query = array('access_token' => $accessToken);
		$options = array('query' => $query, 'body' => $data);

		return SendRequestOperator::sendRequest($client, $method, $url, $options);
	}


	public static function getJsapiTicket($accessToken, $method='GET', $url='/cgi-bin/ticket/getticket', $timeout=self::DEFAULT_HTTP_TIMEOUT){
		$client = new Client(['base_uri' => env('WECHAT_BASE_URI'), 'timeout' => $timeout]);
		$query = array('access_token' => $accessToken, 'type' => 'jsapi');
		$options = array('query' => $query);

		return SendRequestOperator::sendRequest($client, $method, $url, $options);
	}


	public static function getJssdkSignPackage($jsapiTicket, $url){
		$nonceStr = self::createNonceStr(self::NONCE_LENGTH);
		$timestamp = time();

		$tmpStr = "jsapi_ticket=$jsapiTicket&noncestr=$nonceStr&timestamp=$timestamp&url=$url";
		$signature = sha1($tmpStr);

		$signPackage = array(
			'appId' => env('WECHAT_APP_ID'),
			'nonceStr' => $nonceStr,
			'timestamp' => $timestamp,
			'url' => $url,
			'signature' => $signature,
			'rawString' => $tmpStr
			);

		return $signPackage;
	}

	/**
	 * [createMenu 创建自定义菜单]
	 * @param  string/array $data         [自定义菜单描述，json字符串；数组将自动转化为json]
	 * @param  string 		$access_token [微信接口调用凭证，可通过getAccessToken方法获取]
	 * @param  string 		$method       [http请求方法]
	 * @param  string 		$url          [http请求地址]
	 * @param  number 		$timeout      [超时设置，精确到秒；0为不设置]
	 * @return ResponseModel              [返回值]
	 */
	public static function createMenu($data, $access_token, $method='POST', $url='/cgi-bin/menu/create', $timeout=self::DEFAULT_HTTP_TIMEOUT){
		if (is_array($data)) {
			$data = json_encode($data, JSON_UNESCAPED_UNICODE);
		}

		$client = new Client(['base_uri' => env('WECHAT_BASE_URI'), 'timeout' => $timeout]);
		$query = array('access_token' => $access_token);
		$options = array('query' => $query, 'body' => $data);

		return SendRequestOperator::sendRequest($client, $method, $url, $options);
	}


	/**
	 * [getOauthAccessToken 微信网页授权机制获取用户信息，并将请求结果封装为ResponseModel对象]
	 * @param  string $code       [换取access_token的票据]
	 * @param  string $method     [http请求方法]
	 * @param  string $url        [http请求地址]
	 * @param  string $grant_type [填写为authorization_code]
	 * @param  number $timeout    [超时设置，精确到秒；0为不设置]
	 * @return ResponseModel      [返回值]
	 */
	public static function getOauthAccessToken($code, $method='GET', $url='/sns/oauth2/access_token', $grant_type='authorization_code', $timeout=self::DEFAULT_HTTP_TIMEOUT){
		$client = new Client(['base_uri' => env('WECHAT_BASE_URI'), 'timeout' => $timeout]);
		$query = array('appid' => env('WECHAT_APP_ID'), 'secret' => env('WECHAT_APP_SECRET'), 'code' => $code, 'grant_type' => $grant_type);
		$options = array('query' => $query);
		
		return SendRequestOperator::sendRequest($client, $method, $url, $options);
	}


	/**
	 * [createNonceStr 生成随机字符串]
	 * @param  int 		$length [随机字符串长度]
	 * @return string         	[随机字符串]
	 */
	public static function createNonceStr($length){
		$nonce = null;
		$charSource = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz';
		$max = strlen($charSource) - 1;

		for($i = 0; $i < $length; $i++){
			$nonce .= $charSource[rand(0, $max)];
		}

		return $nonce;
	}


	/**
	 * [sendRequest 使用guzzle发送http请求，并将请求结果封装为ResponseModel对象]
	 * @param  Client $client  [guzzle http client]
	 * @param  string $method  [http请求方法]
	 * @param  string $url     [http请求地址]
	 * @param  Array $options  [http请求可选项]
	 * @return ResponseModel   [返回值]
	 */
	// public static function sendRequest($client, $method, $url, $options){
	// 	$result = new ResponseModel();
	// 	try {
	// 		$response = $client->request($method, $url, $options);
	// 	} catch (ConnectException $e) {
	// 		$result->code = ResponseCodeModel::$HttpConnectException;
	// 		return $result;
	// 	}
	// 	$result->code = ResponseCodeModel::$HttpSuccess;
	// 	$result->data = $response->getBody()->getContents();
	// 	return $result;
	// }

		/**
	 * 根据会员的$openId查询会员基本信息
	 * @param  [string] $openId      [会员相当于公众号的openid]
	 * @param  string $lang        [返回国家地区语言版本，zh_CN 简体，zh_TW 繁体，en 英语]
	 * @param  string $method      [请求发起方式]
	 * @param  string $url         [请求地址]
	 * @param  [float] $timeout     [请求超时的秒数, 默认为0，即无限期的等待]
	 * @return [array]              [请求返回的结果]
	 */
	public static function getUserInfo($openId, $accessToken, $lang = 'zh_CN', $method = 'GET', $url = 'cgi-bin/user/info', $timeout = self::DEFAULT_HTTP_TIMEOUT){
        
		$client = new Client(['base_uri' => env('WECHAT_BASE_URI'), 'timeout' => $timeout]);
		$query = array('access_token' => $accessToken, 'openid' => $openId, 'lang' => $lang);
		$options = array('query' => $query);

		$result = SendRequestOperator::sendRequest($client, $method, $url, $options);
		return $result;
	}

    public static function getOAuthUserInfo($data, $method='GET', $url='/sns/userinfo', $lang = 'zh_CN', $timeout=self::DEFAULT_HTTP_TIMEOUT){
        $data = json_decode($data, true);
        $accessToken = $data['access_token'];
        $openId = $data['openid'];
        
		$client = new Client(['base_uri' => env('WECHAT_BASE_URI'), 'timeout' => $timeout]);
		$query = array('access_token' => $accessToken, 'openid' => $openId, 'lang' => $lang);
		$options = array('query' => $query);

		$result = SendRequestOperator::sendRequest($client, $method, $url, $options);
		return $result;
    }

    public static function getOAuthCodeRedirectUrl($redirectUri){
    	$appId = env('WECHAT_APP_ID');
    	return "https://open.weixin.qq.com/connect/oauth2/authorize?appid=$appId&redirect_uri=$redirectUri&response_type=code&scope=snsapi_userinfo&state=konka#wechat_redirect";
    }

    public static function refreshOAuthAccessToken($data, $method='GET', $url='/sns/oauth2/refresh_token', $grant_type='refresh_token', $timeout=self::DEFAULT_HTTP_TIMEOUT){
    	$data = json_decode($data, true);
        $refreshToken = $data['refresh_token'];
        
		$client = new Client(['base_uri' => env('WECHAT_BASE_URI'), 'timeout' => $timeout]);
		$query = array('appid' => env('WECHAT_APP_ID'), 'grant_type' => $grant_type,'refresh_token' => $refreshToken);
		$options = array('query' => $query);

		$result = SendRequestOperator::sendRequest($client, $method, $url, $options);
		return $result;
    }

}
